Imports BitSmoke.Core.Net.Compression
Imports BitSmoke.Core.Net.Connection
Imports BitSmoke.Core.Data

Imports System.Threading

Namespace Core.Net.WorkQueue
    Public Interface IWorkItem
        Function doWork() As Object
    End Interface

    Public Class WI_ParseMessage
        Implements IWorkItem

        Private zBA_Message As Byte()

        Public Sub New(ByVal pBA_Message As Byte())
            zBA_Message = pBA_Message
        End Sub

        Public Function doWork() As Object Implements IWorkItem.doWork
            If zBA_Message.Length < 3 Then
                Debug.WriteLine("Err: Couldn't parse message (too short)")

                Return Nothing
            End If

            Dim iMsgSize As UInt16 = BitConverter.ToUInt16(zBA_Message, 0)
            Dim bID As Byte = zBA_Message(2)
            Dim baOptions As New BitArray(New Byte() {zBA_Message(3)})

            Dim baPayload As Byte() = New Byte(iMsgSize - 4) {}
            Array.ConstrainedCopy(zBA_Message, 4, baPayload, 0, iMsgSize - 4)

            If baOptions(0) Then 'compressed
                baPayload = Compressor.decompress(baPayload)
            End If

            Dim tMsg As Type = DataRoot.getDataRoot.getMessageType(bID)
            If tMsg Is Nothing Then
                Return Nothing
            Else
                Return tMsg.InvokeMember(Nothing, Reflection.BindingFlags.CreateInstance, Nothing, Nothing, New Object() {baPayload})
            End If
        End Function
    End Class

    Public Class BackGroundWorkQueue
        Implements IDisposable

#Region " Private Properties "
        Private zTh As New Thread(AddressOf zTh_Work)
        Private zQueue As New Queue(Of IWorkItem)
        Private zAR_NewWork As New AutoResetEvent(False)
        Private zSL As New Object
        Private zDC As DataConnection
#End Region

#Region " Events "
        Public Event WorkCompleted(ByVal pWI As IWorkItem, ByVal pObj_Result As Object)
#End Region

        Public Sub New(ByVal pDC As DataConnection)
            zDC = pDC

            zTh.Name = GetType(BackGroundWorkQueue).FullName
            zTh.Start()
        End Sub

        Private Sub zTh_Work()
            Dim wi As IWorkItem = Nothing
            Dim bNoWork As Boolean

            Try
                While True
                    SyncLock zSL
                        bNoWork = (zQueue.Count = 0) 'the boolean is just so we can check the count inside a critical section
                    End SyncLock

                    If bNoWork Then
                        zAR_NewWork.WaitOne()
                    End If

                    SyncLock zSL
                        If zQueue.Count > 0 Then
                            wi = zQueue.Dequeue
                        Else
                            wi = Nothing

                            zAR_NewWork.Reset()
                        End If
                    End SyncLock

                    If Not wi Is Nothing Then
                        RaiseEvent WorkCompleted(wi, wi.doWork())
                    End If
                End While
            Catch e As ThreadAbortException
                'shutting down
                Debug.WriteLine("EX: thread shutting down")
            Catch e As Exception
                'if the thread has a problem, the thread dies
                Debug.WriteLine("EX: thread had a problem")
            End Try
        End Sub

        Public Sub addWork(ByVal pWI As IWorkItem)
            SyncLock zSL
                zQueue.Enqueue(pWI)
                zAR_NewWork.Set()
            End SyncLock
        End Sub

#Region " IDisposable Support "
        Private disposedValue As Boolean = False        ' To detect redundant calls

        ' IDisposable
        Protected Overridable Sub Dispose(ByVal disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    'free managed resources when explicitly called
                    zAR_NewWork.Set()
                    zAR_NewWork.Close()
                    zAR_NewWork = Nothing

                    zTh.Abort()
                    zTh = Nothing
                End If

                'free shared unmanaged resources
            End If
            Me.disposedValue = True
        End Sub

        ' This code added by Visual Basic to correctly implement the disposable pattern.
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region

    End Class
End Namespace
